/// Money utility for currency formatting and conversion.
///
/// Original author: Sky24n (https://github.com/Sky24n)
/// Updated by: sunlunchang
library;

import 'num_util.dart';

/// Money unit type.
enum MoneyUnit {
  /// No unit (e.g., 6.00)
  normal,

  /// Yuan symbol (e.g., ¥6.00)
  yuan,

  /// Chinese yuan character (e.g., 6.00元)
  yuanZh,

  /// Dollar symbol (e.g., $6.00)
  dollar,
}

/// Money format type.
enum MoneyFormat {
  /// Keep two decimal places (e.g., 6.00元)
  normal,

  /// Remove trailing zeros (e.g., 6.00元 -> 6元, 6.60元 -> 6.6元)
  endInteger,

  /// Whole yuan only (e.g., 6.00元 -> 6元)
  yuanInteger,
}

/// Money utility class for currency operations.
class MoneyUtil {
  /// Yuan symbol
  static const String yuan = '¥';

  /// Chinese yuan character
  static const String yuanZh = '元';

  /// Dollar symbol
  static const String dollar = '\$';

  /// Converts fen (cents) to yuan with formatting.
  ///
  /// [amount] Amount in fen (1 yuan = 100 fen).
  /// [format] Format type (default: [MoneyFormat.normal]).
  /// Returns formatted yuan string.
  ///
  /// Example: changeF2Y(12345) => '123.45'
  static String changeF2Y(int amount,
      {MoneyFormat format = MoneyFormat.normal}) {
    String moneyTxt;
    final yuanValue = NumUtil.divide(amount, 100);
    switch (format) {
      case MoneyFormat.normal:
        moneyTxt = yuanValue.toStringAsFixed(2);
        break;
      case MoneyFormat.endInteger:
        if (amount % 100 == 0) {
          moneyTxt = yuanValue.toInt().toString();
        } else if (amount % 10 == 0) {
          moneyTxt = yuanValue.toStringAsFixed(1);
        } else {
          moneyTxt = yuanValue.toStringAsFixed(2);
        }
        break;
      case MoneyFormat.yuanInteger:
        moneyTxt = (amount % 100 == 0)
            ? yuanValue.toInt().toString()
            : yuanValue.toStringAsFixed(2);
        break;
    }
    return moneyTxt;
  }

  /// Converts fen string to yuan with format and unit.
  ///
  /// [amountStr] Amount string in fen.
  /// [format] Format type (default: [MoneyFormat.normal]).
  /// [unit] Unit type (default: [MoneyUnit.normal]).
  /// Returns formatted yuan string with unit.
  ///
  /// Example: changeFStr2YWithUnit('12345', unit: MoneyUnit.yuanZh) => '123.45元'
  static String changeFStr2YWithUnit(String amountStr,
      {MoneyFormat format = MoneyFormat.normal,
      MoneyUnit unit = MoneyUnit.normal}) {
    final amount = int.parse(amountStr);
    return changeF2YWithUnit(amount, format: format, unit: unit);
  }

  /// Converts fen to yuan with format and unit.
  ///
  /// [amount] Amount in fen.
  /// [format] Format type (default: [MoneyFormat.normal]).
  /// [unit] Unit type (default: [MoneyUnit.normal]).
  /// Returns formatted yuan string with unit.
  ///
  /// Example: changeF2YWithUnit(12345, unit: MoneyUnit.yuan) => '¥123.45'
  static String changeF2YWithUnit(int amount,
      {MoneyFormat format = MoneyFormat.normal,
      MoneyUnit unit = MoneyUnit.normal}) {
    return withUnit(changeF2Y(amount, format: format), unit);
  }

  /// Formats yuan value with unit.
  ///
  /// [yuanValue] Yuan value (can be int, double, or string).
  /// [unit] Unit type.
  /// [format] Optional format type.
  /// Returns formatted yuan string with unit.
  ///
  /// Example: changeYWithUnit(123.45, MoneyUnit.yuanZh) => '123.45元'
  static String changeYWithUnit(Object yuanValue, MoneyUnit unit,
      {MoneyFormat? format}) {
    String yuanTxt = yuanValue.toString();
    if (format != null) {
      final amount = changeY2F(yuanValue);
      yuanTxt = changeF2Y(amount.toInt(), format: format);
    }
    return withUnit(yuanTxt, unit);
  }

  /// Converts yuan to fen.
  ///
  /// [yuanValue] Yuan value (can be int, double, or string).
  /// Returns amount in fen.
  ///
  /// Example: changeY2F(123.45) => 12345
  static int changeY2F(Object yuanValue) {
    return NumUtil.multiplyDecStr(yuanValue.toString(), '100')
        .toBigInt()
        .toInt();
  }

  /// Adds currency unit to money text.
  ///
  /// [moneyTxt] Money text without unit.
  /// [unit] Unit type to add.
  /// Returns money text with unit.
  ///
  /// Example: withUnit('123.45', MoneyUnit.yuan) => '¥123.45'
  static String withUnit(String moneyTxt, MoneyUnit unit) {
    switch (unit) {
      case MoneyUnit.yuan:
        moneyTxt = yuan + moneyTxt;
        break;
      case MoneyUnit.yuanZh:
        moneyTxt = moneyTxt + yuanZh;
        break;
      case MoneyUnit.dollar:
        moneyTxt = dollar + moneyTxt;
        break;
      default:
        break;
    }
    return moneyTxt;
  }
}
